package com.ease.concurrent;

import java.util.concurrent.CountDownLatch;

import com.ease.common.util.Assertion;

/**
 * @author nathanleewei
 */
public class ConcurrentWholesaleExecutor extends ConcurrentExecutor {

	protected int taskSize = 0;

	protected boolean blockingMainThread = false;

	protected boolean concurrentExecution = false;

	public void execute(final ConcurrentWholesaleCallback<Object> concurrentWholesaleCallback) throws InterruptedException {

		Assertion.isPositive(taskSize, "taskSize must > 0");
		CountDownLatch begin = null;
		CountDownLatch end = null;

		if (this.isConcurrentExecution()) {
			begin = new CountDownLatch(1);
		}

		if (this.isBlockingMainThread()) {
			end = new CountDownLatch(taskSize);
		}
		// final long startTime = System.nanoTime();
		final CountDownLatch beginLatch = begin;
		final CountDownLatch endLatch = end;

		for (int i = 0; i < taskSize; i++) {
			final int taskIndex = i;
			this.getThreadPoolTaskExecutor().execute(new Runnable() {
				public void run() {
					try {
						if (null != beginLatch) {
							beginLatch.await();
						}
						concurrentWholesaleCallback.execute(taskIndex);
					} catch (Throwable e) {
						e.printStackTrace();
					} finally {
						if (null != endLatch) {
							endLatch.countDown();
						}
					}
					// System.out.println("taskIndex:" + taskIndex +
					// ", elapsed: " + (System.nanoTime() - startTime));
				}
			});
		}

		if (this.isConcurrentExecution()) {
			begin.countDown();
		}

		if (this.isBlockingMainThread()) {
			end.await();
		}

		if (isShutdownOnCompleted()) {
			// 多线程调用主程序怎么办?
			shutdown();
		}
	}

	/**
	 * @return the taskSize
	 */
	public int getTaskSize() {
		return taskSize;
	}

	/**
	 * @param taskSize
	 *            the taskSize to set
	 */
	public void setTaskSize(int taskSize) {
		this.taskSize = taskSize;
	}

	/**
	 * @return the blockingMainThread
	 */
	public boolean isBlockingMainThread() {
		return blockingMainThread;
	}

	/**
	 * @param blockingMainThread
	 *            the blockingMainThread to set
	 */
	public void setBlockingMainThread(boolean blockingMainThread) {
		this.blockingMainThread = blockingMainThread;
	}

	/**
	 * @return the concurrentExecution
	 */
	public boolean isConcurrentExecution() {
		return concurrentExecution;
	}

	/**
	 * @param concurrentExecution
	 *            the concurrentExecution to set
	 */
	public void setConcurrentExecution(boolean concurrentExecution) {
		this.concurrentExecution = concurrentExecution;
	}

}
